﻿namespace BEGDC.CC.Web.EZVisit.Controls
{
    #region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using ASBCC.Database.Entity;
    using ASBCC.Database.Service;
    using ASBCC.Workflow.K2Manager;
    using BL.Common;
    using BL.Common.Query;
    using Utility.Castle;
    using Utility.Extensions;

    #endregion

    public class EZVRequestBaseControl : UserControl
    {
        private CustomValidator validator;

        #region Properties

        /// <summary>
        /// Gets or sets the session key.
        /// </summary>
        /// <value>
        /// The session key.
        /// </value>
        public string SessionKey
        {
            get
            {
                return Convert.ToString(this.ViewState["SessionKey"]);
            }
            set
            {
                this.ViewState["SessionKey"] = value;
            }
        }

        /// <summary>
        /// Gets or sets the <see cref="ASBCC.Database.Entity.EZVisitApplicationTableEntity"/> object.
        /// </summary>
        /// <value>
        /// The  <see cref="ASBCC.Database.Entity.EZVisitApplicationTableEntity"/> object.
        /// </value>
        protected EZVisitApplicationTableEntity EZVisitApplication
        {
            get
            {
                return this.Session[this.SessionKey] as EZVisitApplicationTableEntity;
            }
            set
            {
                this.Session[this.SessionKey] = value;
            }
        }

        /// <summary>
        /// Gets or sets the current login user.
        /// </summary>
        /// <value>
        /// The current user name.
        /// </value>
        public string CurrentUser
        {
            get
            {
                return Convert.ToString(this.ViewState["CurrentUser"]);
            }
            set
            {
                this.ViewState["CurrentUser"] = value;
            }
        }

        /// <summary>
        /// Gets or sets the type of the current action.
        /// </summary>
        /// <value>
        /// The type of the current action.
        /// </value>
        public string CurrentActionType
        {
            get
            {
                return Convert.ToString(this.ViewState["CurrentActionType"]);
            }
            set
            {
                this.ViewState["CurrentActionType"] = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="EZVRequestBaseControl"/> is editable.
        /// </summary>
        /// <value>
        ///   <c>true</c> if editable; otherwise, <c>false</c>.
        /// </value>
        public bool Editable
        {
            get
            {
                return Convert.ToBoolean(this.ViewState["Editable"]);
            }
            set
            {
                this.ViewState["Editable"] = value;
            }
        }

        #endregion

        #region View

        protected virtual bool NeedValidate
        {
            get
            {
                return this.Visible && this.Editable;
            }
        }

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Load"/> event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnLoad(EventArgs e)
        {
            if (this.NeedValidate)
            {
                this.validator = new CustomValidator { ID = "cv1", ValidationGroup = "ValidateSubmit", EnableClientScript = false };
                this.validator.ServerValidate += OnServerValidate;
                this.Page.Validators.Add(this.validator);
            }

            base.OnLoad(e);
        }

        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected virtual void Page_Load(object sender, EventArgs e)
        {
            if (this.Visible && !this.IsPostBack)
            {
                this.PreRenderPartialView();
            }
        }

        /// <summary>
        /// Pre-render partial view method.
        /// </summary>
        protected virtual void PreRenderPartialView()
        {
            this.SetViewData();
            this.SetVisibility();
        }

        /// <summary>
        /// Sets the data of controls.
        /// </summary>
        protected virtual void SetViewData()
        {
        }

        /// <summary>
        /// Sets the visibility of controls.
        /// if the control is editable, controls whose names start with "edt_" will be displayed and names with "vw_" will be hidden.
        /// if the control is not editable, controls whose names start with "vw_" will be displayed and names with "edt_" will be hidden.
        /// </summary>
        protected virtual void SetVisibility()
        {
            var controls = GetAllControls(this);

            foreach (Control c in from Control c in controls where c.ID != null select c)
            {
                if (c.ID.StartsWith(EZVRequest.EditModePrefix))
                {
                    c.Visible = this.Editable;
                }
                else if (c.ID.StartsWith(EZVRequest.ViewModePrefix))
                {
                    c.Visible = !this.Editable;
                }
            }
        }

        #endregion

        /// <summary>
        /// Validates the EZVisit application.
        /// </summary>
        /// <param name="actionType">Type of the action.</param>
        /// <param name="error">The error message.</param>
        /// <returns><c>true</c> if data validation passed else <c>false</c></returns>
        protected virtual bool Validate(out string error)
        {
            error = string.Empty;
            return true;
        }

        public virtual void Save(EZVisitApplicationTableEntity app)
        {
            this.SaveApplication(app);
        }

        private void SaveApplication(EZVisitApplicationTableEntity app)
        {
            if (app == null)
            {
                throw new ArgumentNullException("app");
            }

            string actionType = this.CurrentActionType;

            switch (actionType)
            {
                case K2ActionType.Save:
                case K2ActionType.Submit:
                case K2ActionType.Resubmit:

                    var catBranch = this.Page.FindControl("ddlCATBranch") as DropDownList;

                    if (catBranch != null && catBranch.Visible)
                    {
                        var catBranchInfo = catBranch.SelectedValue.Split(';');

                        app.CATBranch = catBranch.SelectedItem.Text;

                        app.DepartmentType = Convert.ToInt32(catBranchInfo[1]);
                        app.DepartmentName = Convert.ToInt32(catBranchInfo[2]);
                        app.AllDept = catBranchInfo[3];
                        app.Region = catBranchInfo[4];

                        var account = this.Parent.FindControl("ddlAccount") as DropDownList;

                        if (account != null)
                        {
                            app.Account = catBranchInfo[0].VariantEquals("Branch") ? account.SelectedValue : string.Empty;
                        }
                    }

                    bool isDraft = actionType.Equals(K2ActionType.Save);

                    if (actionType.Equals(K2ActionType.Submit))
                    {
                        app.SubmitDate = DateTime.Now;

                        isDraft = !this.Page.IsValid;
                    }

                    if (app.AllDept.IsNotNullOrWhiteSpace())
                    {
                        app.AppNo = GenerateAppNo(app.AppNo, app.AllDept, app.Account, isDraft);

                        // Refresh the AppNo.
                        var lblAppNo = this.Page.FindControl("lbAppNo") as Label;
                        var lblAppNo1 = this.Page.FindControl("lblAppNo") as Label;

                        if (lblAppNo != null && lblAppNo1 != null)
                        {
                            lblAppNo.Text = lblAppNo1.Text = "&nbsp;&nbsp;Application No：" + app.AppNo;
                        }
                    }

                    break;
                case K2ActionType.PostSubmit:
                    app.AftSubmitDate = DateTime.Now;
                    break;
                case K2ActionType.Approve:
                    if (app.EZVisitReqNo == null)
                    {
                        app.EZVisitReqNo = GenerateRequestNo();
                    }
                    break;
                case K2ActionType.Withdraw:
                    app.Readers = null;
                    app.FNCController = null;
                    app.DeptHead = null;
                    app.PDC = null;
                    app.CODPPManager = null;
                    app.CODPPHead = null;
                    app.LGD = null;
                    app.LGDCheckPerson = null;
                    app.FNCControllerDate = new DateTime?();
                    app.DeptHeadDate = new DateTime?();
                    app.PDCDate = new DateTime?();
                    app.CODPPCheckPersonDate = new DateTime?();
                    app.CODPPManagerDate = new DateTime?();
                    app.CEODelegationDate = new DateTime?();
                    app.CODPPHeadDate = new DateTime?();
                    app.LGDDate = new DateTime?();
                    app.LGDCheckPersonDate = new DateTime?();
                    app.AppNo = GenerateAppNo(app.AppNo, app.AllDept, app.Account, true);

                    break;
            }

            if (app.AppID == null)
            {
                EZVisitApplicationManager.Insert(app);
            }
            else
            {
                app.LastUpdateBy = this.CurrentUser;
                app.LatestUpdateAt = DateTime.Now;

                EZVisitApplicationManager.Update(app);
            }

            // Have to reload session. Ugly but necessary.
            this.EZVisitApplication = app;
        }

        #region Helpers

        /// <summary>
        /// Generates the EZVisit Application No.
        /// </summary>
        /// <param name="prevAppNo">The prev Application No.</param>
        /// <param name="catBranch">The selected CAT/Branch.</param>
        /// <param name="account">The selected customer.</param>
        /// <param name="isDraft">Is the application in a DRAFT status?</param>
        /// <returns>Application No.</returns>
        public static string GenerateAppNo(string prevAppNo, string catBranch, string account, bool isDraft)
        {
            int maxId;

            if (prevAppNo.IsNotNullOrWhiteSpace())
            {
                prevAppNo = prevAppNo.Replace("-D", string.Empty);

                maxId = int.Parse(prevAppNo.Substring(prevAppNo.Length - 4));
            }
            else
            {
                var queryService = (IQuery)AppContainer.Instance[ServiceConst.QueryService];

                maxId = queryService.GetMaxIdForEZVisit(isDraft ? 0 : 1);
            }

            if (string.IsNullOrEmpty(account))
            {
                account = catBranch;
                catBranch = "HQ";
            }

            string format;

            string d = isDraft ? "-D" : string.Empty;

            return string.Format("{0}{1}-Y{2}-{3:0000}{4}", catBranch, account, DateTime.Now.ToString("yy"), maxId, d);
        }

        /// <summary>
        /// Generates the EZVisit Request No.
        /// </summary>
        /// <returns>Request No.</returns>
        private static string GenerateRequestNo()
        {
            var queryService = (IQuery)AppContainer.Instance[ServiceConst.QueryService];

            int maxId = queryService.GetMaxIdForEZVisit(2);

            return string.Format("{0}-{1:000}", DateTime.Now.ToString("yy"), maxId);
        }

        private static IEnumerable<Control> GetAllControls(Control parent)
        {
            foreach (Control control in parent.Controls)
            {
                if (control.ID != null)
                {
                    yield return control;
                }

                foreach (Control descendant in GetAllControls(control))
                {
                    yield return descendant;
                }
            }
        }

        protected void OnServerValidate(object source, ServerValidateEventArgs args)
        {
            string error;

            args.IsValid = this.Validate(out error);
            this.validator.ErrorMessage = error;
        }

        #endregion
    }
}